<template>
  <div class="WebSocket">
    <div class="">
      <h3>WebSocket Demo</h3>
      <textarea
        name="contenttext"
        v-model="textarea"
        id="contenttext"
        cols=""
        rows=""
        style="width: 300px; height: 200px"
      ></textarea>
      <div class="button" @click="sendhandler">发送</div>
    </div>
    <div class="list">
      <div class="item" v-for="(item, index) in MessageArray" :key="index">
        <div :class="item.flag == 1 ? 'initiative' : 'system'">
          <span>{{ item.role }}</span>
          <span>-----</span>
          <span>{{ item.time }}</span>
        </div>
        <p v-if="item.flag == 1">{{ item.text }}</p>
        <p v-else v-html="item.text"></p>
      </div>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
import { Message } from '@/common/util.js'

// 心跳检测
var heartCheck = {
  timeout: 60000, // 60秒
  timeoutObj: null,
  serverTimeoutObj: null,
  reset: function () {
    clearTimeout(this.timeoutObj)
    clearTimeout(this.serverTimeoutObj)
    return this
  },
  start: function (ws) {
    var self = this
    this.timeoutObj = setTimeout(function () {
      // 这里发送一个心跳，后端收到后，返回一个心跳消息，
      // onmessage拿到返回的心跳就说明连接正常
      ws.send('HeartBeat')
      self.serverTimeoutObj = setTimeout(function () {
        // 如果超过一定时间还没重置，说明后端主动断开了
        ws.close() // 如果onclose会执行reconnect，我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
      }, self.timeout)
    }, this.timeout)
  }
}
export default {
  name: 'WebSocket',
  data () {
    return {
      textarea: '',
      wsUrl: 'ws://121.40.165.18:8800', // ws wss
      lockReconnect: false, // 避免重复连接
      maxReconnect: 5, // 最大重连次数，若连接失败
      ws: null, // WebSocket实例
      MessageArray: []
    }
  },
  components: {},
  mounted () {
    this.createWebSocket(this.wsUrl)
  },
  methods: {
    createWebSocket (url) {
      // console.log('WebSocket准备握手')
      // console.log('实例化WebSocket')
      this.MessageArray.push(new Message('我', this.GainTime(), 'WebSocket准备握手', '1'))
      try {
        if ('WebSocket' in window) {
          this.ws = new WebSocket(url)
        } else if ('MozWebSocket' in window) {
          // this.ws = new MozWebSocket(url)
        } else {
          const url = 'http://' + 'xxxxxxx'
          console.log(url)
          // this.ws = new SockJS(url)
        }

        this.initEventHandle()
      } catch (e) {
        this.reconnect(url)
      }
    },
    initEventHandle () {
      this.ws.onclose = function (evnt) {
        // console.log('WebSocket服务关闭了', evnt)
        this.MessageArray.push(new Message('服务器', this.GainTime(), 'WebSocket服务关闭了', '2'))

        // 这个在正常使用的时候需要放开  重新链接WebSocket
        // this.reconnect(this.wsUrl)
      }.bind(this)
      this.ws.onerror = function (evnt) {
        console.log('WebSocket服务出错了', evnt)
        this.reconnect(this.wsUrl)
      }.bind(this)
      this.ws.onopen = function (evnt) {
        // console.log('WebSocket握手成功')

        this.MessageArray.push(new Message('我', this.GainTime(), 'WebSocket握手成功', '1'))
        this.MessageArray.push(new Message('服务器', this.GainTime(), 'WebSocket连接已建立，正在等待数据...', '2'))
        // 心跳检测重置
        heartCheck.reset().start(this.ws)
      }.bind(this)
      this.ws.onmessage = function (evnt) {
        // 如果获取到消息，心跳检测重置
        // 拿到任何消息都说明当前连接是正常的
        // console.log('WebSocket服务获得数据了', evnt)

        // 接受消息后的UI变化
        this.doWithMsg(evnt.data)
        heartCheck.reset().start(this.ws)
      }.bind(this)
    },
    // 收到消息推送
    doWithMsg (message) {
      this.MessageArray.push(new Message('服务器', this.GainTime(), message, '2'))
      // console.log('收到后端消息', message)
      // ......
    },

    // 重新连接
    reconnect (url) {
      console.log('WebSocket尝试重新链接')
      // console.log(this.maxReconnect--)
      if (this.lockReconnect || this.maxReconnect <= 1) {
        return console.log('WebSocket关闭重新链接')
      }
      this.lockReconnect = true
      // 没连接上会一直重连，设置延迟避免请求过多
      setTimeout(
        function () {
          this.maxReconnect--
          this.createWebSocket(url)
          this.lockReconnect = false
        }.bind(this),
        2000
      )
    },

    sendhandler () {
      // console.log(this.ws.readyState)
      if (this.ws.readyState === 0) {
        alert('WebSocket正在链接中')
      } else if (this.ws.readyState === 1) {
        this.MessageArray.push(new Message('我', this.GainTime(), this.textarea, '1'))
        this.ws.send(this.textarea)
        this.textarea = ''
      } else if (this.ws.readyState === 2) {
        alert('WebSocket连接正在关闭')
      } else if (this.ws.readyState === 3) {
        alert('WebSocket连接已关闭或者没有链接成功')
      }
    },
    GainTime () {
      const date = new Date()
      const year = date.getFullYear() // 获取当前年份
      const mon = date.getMonth() + 1 // 获取当前月份
      const day = date.getDate() // 获取当前日
      const hour = date.getHours() // 获取当前时
      const min = date.getMinutes() // 获取当前分
      const second = date.getSeconds() // 获取当前秒
      const milliSecond = date.getMilliseconds() // 获取当前毫秒
      return (
        year +
        '/' +
        mon +
        '/' +
        day +
        ' ' +
        hour +
        ':' +
        min +
        ':' +
        second +
        ':' +
        milliSecond
      ) // 拼接获取到的当前系统年月日时分秒
    },
    scrollToBottom () {
      this.$nextTick(() => {
        // Vue 在更新 DOM 时是异步执行的，为了在数据变化之后等待 Vue 完成更新 DOM，可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。
        var container = this.$el.querySelector('.list') // 这里的class是我盛放数据流设置了overflow:auto 也就是让其拥有滚动条的盒子，自己根据情况去选定元素
        container.scrollTop = container.scrollHeight
      })
    }
  },
  updated: function () { // 监听数据变化的钩子函数
    this.scrollToBottom() // 每次页面渲染完之后滚动条在最底部
  },
  destroyed () {
    this.ws.close()
  }
}
</script>

<style scoped lang="scss">
.WebSocket {
  display: flex;
  .button {
    text-align: center;
    width: 300px;
    height: 34px;
    line-height: 34px;
    background-color: #5bc0de;
    border-radius: 4px;
    color: #fff;
    font-weight: bold;
    cursor: pointer;
  }
  .list {
    width: 50%;
    height: 300px;
    border: 1px solid #ccc;
    overflow-y: scroll;
    .item{
      .initiative{
        color: #008000;
      }
      .system{
        color: #0000ff;
      }
    }
  }
}
</style>
